home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d20
/
pxsrc21a.arc
/
PAKSORTM.C
< prev
next >
Wrap
Text File
|
1991-05-12
|
14KB
|
554 lines
/*
PAKSORTM.C Sort contents of .ARC archive.
Copyright 1989 by Jeffrey J. Nonken
Released to public domain.
Modified from PAKSORT.C: Copyright 1988, Michael J. Housky
Released to the Public Domain ... *no* rights reserved.
I ripped off Mike's code from the stand-alone program PAKSORT in
order to include it into PolyXarc as a module. The only changes I
made were: stripped the main() function out, removed the order[]
variable and hard-coded the sort order, and added code to record
the highest compression type value (so I can tell whether to use
ARCE, PKUNPAK, or PAK) to discombobulate. I also now allocate the
buffer, rather than having a fixed buffer size.
*/
/*
Update log:
12 May 1991: Separated header errors from open/read errors; header
errors now return 6 instead of 1 so we know that we can rename
them and go on if we're doing bundles.
18 September 1990: added support for type 1 headers (which are 4 bytes
shorter than all other header types); added support for version 6
archives. Version 6 archives have some advanced stuff that version
5 archives don't have, and some of it is position dependent, so we
WON'T sort version 6 archives. Since PKPAK never got past version 5
headers, that's not a problem. Type 1 headers are considered obsolete,
but I wouldn't want this to bomb for such a stupid reason. Removed
.olen from the local header stuff; it's not used for anything once
we've tested the header for validity. jjn
22 March 1990: added Amiga stuff. jjn & smp
14 November 1989: modified from PAKSORT.C. jjn
PAKSORT.C update log:
Version 1.1, 24 January 1989: changed default extension .PAK to .ARC. jjn
Version 1.0, 25 August 1988: First version.
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef AMIGA
# include <io.h>
#endif
#ifdef AMIGA
#define _NEAR_
#endif
#ifdef TURBOC
#define _NEAR_
#endif
#ifdef MSC
#include <malloc.h>
#define _NEAR_ near
#endif
#include "p_common.h"
#include "pakmdefn.h"
#define MAX_BUFSIZE 32760
typedef struct /* stored directory format: */
{
int32 floc; /* byte location of header in file */
int32 slen; /* stored (packed) length of file */
/* int32 olen; * original (unpacked) length of file */
word16 ddate; /* DOS date of update */
word16 dtime; /* DOS time of update */
char fname[13]; /* filename */
unsigned char type; /* Header type. */
} pak_dir;
/* ------------ Global data: */
byte * _NEAR_ pak_buf; /* buffer for reading pakfile data */
pak_hdr _NEAR_ fhdr; /* buffer for reading pakfile header */
long _NEAR_ pakloc; /* location in input file */
long _NEAR_ pakloc,
_NEAR_ paklen; /* length of input file */
int _NEAR_ memory;
int16 _NEAR_ highest_type;
int16 _NEAR_ version6; /* True if version 6 header. */
extern int _NEAR_ quiet;
/*****************************************************************************
This will turn an Intel-format integer into a Motorola-format integer.
*****************************************************************************/
#ifdef MOTOROLA
void swap_Intel(char *address, int numbytes)
{
register int i; /* Ascending index. */
register int j; /* Descending index. */
char c; /* Temporary storage for the swap. */
for (i = 0, j = numbytes - 1; i < j; ++i, --j)
{
c = address[i];
address[i] = address[j];
address[j] = c;
}
}
#endif
/*
read_pakhdr: Read header of .ARC member file
Reads next header sequentially from file.
Returns 0 if good header, and global fhdr has header.
Returns +1 if end of file marker found.
Returns -1 if bad header or read error.
*/
int read_pakhdr(FILE *fp)
{
register int i;
i = fgetc(fp); /* get file marker */
if ( i != PAK_MARK ) /* error if not correct */
return -1;
i = fread( (char*)&fhdr, 1, PAK_HDRLEN, fp );
/* read header, follows mark */
#ifdef MOTOROLA
swap_Intel((char *)&fhdr.slen ,sizeof(fhdr.slen) );
swap_Intel((char *)&fhdr.ddate,sizeof(fhdr.ddate));
swap_Intel((char *)&fhdr.dtime,sizeof(fhdr.dtime));
swap_Intel((char *)&fhdr.crc ,sizeof(fhdr.crc) );
swap_Intel((char *)&fhdr.olen ,sizeof(fhdr.olen) );
#endif
if ( i>=1 && fhdr.type==0 ) /* type 0 header is an EOF mark */
return 1; /* end of file mark seen */
if (fhdr.type == 1) /* Header type 1 is 4 bytes short. */
{
fhdr.olen = fhdr.slen; /* Use the stored length. */
fseek(fp,-4l,1); /* Seek relative backwards by 4. */
}
if ( i!=PAK_HDRLEN || fhdr.slen<0L)
return -1; /* invalid header seen */
if (fhdr.type < 20 && fhdr.olen < fhdr.slen)
return -1; /* invalid header seen */
pakloc = ftell(fp); /* note start of data and test */
if ( pakloc+fhdr.slen > paklen ) /* for all data present */
return -1; /* no: presume truncated file */
return 0;
} /* read_pakhdr */
/*
pak_getdir: Build directory of .ARC file headers.
Sequentially read and validate all headers within pakfile. Build malloc-ed
table of headers found.
Returns:
0 = success, *pdirp = pointer to malloc-ed directory.
1 = out of memory;
-1 = read/seek error or bad header.
*/
int pak_getdir( FILE *fp, pak_dir **pdirp )
{
register int i;
int n,k;
long hdrloc;
pak_dir *pd;
/* Read the first header: */
highest_type = 0; /* Init the highest compression type. */
version6 = FALSE; /* Haven't found version 6 stuff yet. */
hdrloc = ftell(fp);
i = read_pakhdr(fp); /* Get the first header. */
if ( i )
{
printf("Invalid header seen.\n");
return -1;
}
pd = (pak_dir*) malloc( (k=32)*sizeof(pak_dir) );
if ( pd==NULL )
{
printf("Out of memory.\n");
memory = 1;
return -1; /* out of memory error */
}
n = 0;
do /* loop once for each new entry found, with */
{ /* n=#headers found, k=directory size */
if ( n >= k ) /* test for current table full */
{
/* add 10 more entries to directory: */
pd = (pak_dir*) realloc( (char*)pd, (k+=16)*sizeof(pak_dir) );
if ( pd==NULL )
{
printf("Out of memory.\n");
memory = 1;
return -1; /* out of memory error */
}
}
if (fhdr.type < 20)
{
if (fhdr.type > (char)highest_type)
highest_type = fhdr.type;
}
else
version6 = TRUE;
pd[n].type = fhdr.type; /* Copy header type. */
pd[n].floc = hdrloc; /* store header location */
pd[n].slen = fhdr.slen; /* copy stored length */
/* pd[n].olen = fhdr.olen; * copy original length */
pd[n].ddate = fhdr.ddate; /* copy DOS date */
pd[n].dtime = fhdr.dtime; /* copy DOS time */
strcpy(pd[n].fname,fhdr.fname); /* copy file name */
++n; /* and increment file count */
hdrloc += fhdr.slen+PAK_HDRLEN+1;
if (fhdr.type == 1) /* Type 1 header is shorter! */
hdrloc -= 4; /* If type 1, reduce by 4. */
i = fseek( fp, hdrloc, SEEK_SET );
if ( i )
{
printf("Seek error.\n");
free( (char*)pd );
return -1;
}
i = read_pakhdr(fp);
} while ( i==0 );
if ( i<0 ) /* test for error */
{
printf("Invalid header seen.\n");
free( (char*)pd );
return -1;
}
*pdirp = pd;
return n;
} /* pak_getdir */
/*
dir_cmp: Directory entry compare function for sort.
Input:
lp: pointer to "left" entry
rp: pointer to "right" entry
Return:
0 if entries are equal
positive if left "greater than" right
negative if left "less than" right
*/
int dir_cmp(pak_dir *lp, pak_dir *rp)
{
register int j;
/* compare unsigned date: */
j = (lp->ddate > rp->ddate) - (lp->ddate < rp->ddate);
if (!j)
/* compare unsigned time: */
j = (lp->dtime > rp->dtime) - (lp->dtime < rp->dtime);
if (!j)
/* compare full fileid */
j = strcmp( lp->fname, rp->fname );
return j;
} /* dir_cmp */
/*
pak_sort: Sort one .ARC file.
A simple (slow, but small and sure) routine is used here to
sort the directory without the overhead of qsort and recursion.
If this sort is replaced with an unstable sort (like quicksort) then
the dir_cmp function should be changed to return compare of original
file location if all fields compare equal. This will preserve
sort stability ... i.e. input order is preserved on equal entries.
Return value is 0 if all files were originally in order,
or 1 if output order is different from input order.
*/
int pak_sort( pak_dir *pdir, int n)
{
register int i,j;
int i0,j0,k,r;
pak_dir tdir;
r = 0;
for ( j0=1; j0<n; ++j0 )
{
i = i0 = j0-1; /* starting entry # to compare */
for ( j=j0; j<n; ++j )
{
k = dir_cmp( pdir+i, pdir+j);
if ( k>0 )
{ /* out of order */
i = j; /* will swap at end */
}
}
if ( i != i0 ) /* if out of order */
{
tdir = pdir[i]; /* swap smallest entry */
pdir[i] = pdir[i0]; /* (at most n-1 times) */
pdir[i0] = tdir;
r = 1; /* tell caller that input was */
/* not in order */
}
}
return r;
} /* pak_sort */
/*
pak_write: Copy packed source files to dest in sorted order.
*/
int pak_write( FILE *src, FILE *dst, pak_dir* dirp, int n )
/* FILE *src; * opened source file */
/* FILE *dst; * opened dest file */
/* pak_dir *dirp; * sorted directory of source */
/* int n; * number of entries in source directory */
{
register int i,j;
int k;
int buf_size;
long len,start,end;
buf_size = MAX_BUFSIZE;
do
{
pak_buf = malloc(buf_size);
if (pak_buf == NULL)
buf_size >>= 1;
} while (pak_buf == NULL && buf_size > 0);
if (pak_buf == NULL)
{
printf("Out of memory.\n");
memory = 1;
return -1;
}
for ( i=0; i<n; ++i )
{ /* once for each member file */
len = dirp[i].slen + 1 +
((1 == dirp[i].type) ? (PAK_HDRLEN - 4) : PAK_HDRLEN);
if (!quiet)
{
printf(" Copying: %-13s - loc=%-6ld len=%-6ld\n",
dirp[i].fname,
dirp[i].floc,
len);
}
/* point to start of member, test for error: */
j = fseek(src, dirp[i].floc, SEEK_SET);
if ( j )
{
printf("Seek error.\n");
free(pak_buf);
return -1;
}
/* copy member to destination: */
for ( end=0; end<len; )
{
start = end;
end = start+(k=buf_size);
if (end>len)
k = (int)((end=len)-start);
j = fread( pak_buf, 1, k, src );
if ( j != k )
{
printf("Read error.\n");
free(pak_buf);
return -1;
}
j = fwrite( pak_buf, 1, k, dst );
if ( j != k )
{
printf("Write error.\n");
free(pak_buf);
return -1;
}
}
}
free(pak_buf);
/* Add EOF mark to (end of) destination: */
fputc( PAK_MARK, dst );
fputc( '\0', dst );
if ( ferror(dst) )
{
printf("Write error.\n");
return -1;
}
return 0;
} /* pak_write */
/*
pak_dosort: Read/sort/rewrite one .ARC file.
Returns 0 if successful, or error:
1 = Can't open/read source. (missing pakfile or DOS error)
2 = Can't create/write dest. (maybe disk or directory full)
3 = Can't delete old source file. (read-only)
4 = Can't rename temp file to source name. (DOS error)
5 = Out of memory.
6 = Invalid pakfile. (Header error)
*/
int pak_dosort(char *fpath, char *fn, int sort)
{
register int i,j;
int n;
pak_dir *pdir; /* pointer to (malloced) directory */
/* built by pak_getdir */
FILE *src; /* source file */
FILE *dst; /* source file */
char *fnptr; /* location of filename in fname */
#ifdef AMIGA
char srcname[108];
char fname[108];
#else
char srcname[64]; /* save source filename */
char fname[64];
#endif
memory = 0;
strcpy(fname,fpath);
fnptr = fname + strlen(fname);
strcpy(fnptr,fn); /* make full path to file */
if (!quiet)
printf("Searching: %s\n",fname); /* and identify */
src = fopen( fname, "rb" ); /* and open file */
if ( src==NULL )
{
printf("Can't open %s.\n", fname);
return 1;
}
#ifdef AMIGA
fseek (src, 0L, SEEK_END);
paklen = ftell(src);
fseek (src, 0L, SEEK_SET);
#else
paklen = filelength(fileno(src)); /* get file length in global */
#endif
pdir = NULL; /* clear directory pointer */
n = pak_getdir( src, &pdir ); /* get directory */
if (memory)
return 5;
if ( n<1 )
{
printf("Invalid file format, not changed.\n");
fclose(src);
return 6;
}
if (version6 || !sort) /* Don't sort if version 6 format. */
{
free( (char*)pdir );
fclose(src); /* unconditionally close source */
return 0;
}
i = pak_sort( pdir, n);
if ( i==0 )
{
printf("Already in order, not changed.\n");
free( (char*)pdir );
fclose(src); /* unconditionally close source */
return 0;
}
/* pakfile is not in order, create sorted copy & rename: */
strcpy( srcname, fname );
strcpy( fnptr, "PAKSRTMP.$$$" );
dst = fopen( fname, "wb" );
if ( dst==NULL )
{
printf("Can't create: %s\n", fname );
free( (char*)pdir );
return 1;
}
j = pak_write( src, dst, pdir, n ); /* copy source to dest tempfile */
fclose(src); /* unconditionally close source */
free( (char*)pdir ); /* and release directory mem */
i = fclose(dst); /* close dest file */
if ( j || i ) /* if error on write or close */
{
if ( !j ) /* identify close error */
printf("Can't close: %s\n",fname);
unlink(fname);
return 2;
}
j = unlink(srcname); /* delete source */
if ( j )
{ /* can't delete, read-only? */
printf( "Can't delete original.\n");
unlink(fname); /* delete sorted temp copy */
return 3; /* return error */
}
j = rename( fname, srcname );
if ( j )
{
printf("Rename error: %d, original unsorted data lost!\n");
printf("Sorted data retained in temp output file for recovery:\n");
printf("%s\n",fname);
return 4;
}
return 0;
} /* pak_dosort */